package com.payneteasy.superfly.demo.web.security;

import com.payneteasy.superfly.demo.web.utils.SecurityUtils;
import org.apache.wicket.Component;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authorization.IAuthorizationStrategy;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.request.component.IRequestableComponent;
import org.springframework.security.annotation.Secured;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.StringTokenizer;

public class SpringSecurityAuthorizationStrategy implements IAuthorizationStrategy {
	
	private static final String DEV_FILE_PATH = "src/main/resources/components-security.properties";
	private static final String PROD_FILE_PATH = "components-security.properties";
	
	/**
	 * Used only in production mode (i.e. when properties are loaded from the classpath).
	 */
	private Properties cachedProperties = null;

    public <T extends IRequestableComponent> boolean isInstantiationAuthorized(Class<T> componentClass) {
        return true;
    }

    public boolean isActionAuthorized(Component component, Action action) {
        boolean ret ;
        String path = component.getPage().getClass().getSimpleName()+"."+component.getId()+"."+action.getName();
        String superPath = component.getPage().getClass().getSuperclass().getSimpleName()+"."+component.getId()+"."+action.getName();

        Properties securityProperties = loadSecurityProperties();
        if(isInSecurityPath(path, securityProperties)) {
            ret = isComponentAllowed(path, securityProperties);
        } else if(isInSecurityPath(superPath, securityProperties)) {
            ret = isComponentAllowed(superPath, securityProperties);
        } else if (component.getClass().isAnnotationPresent(Secured.class)) {
            ret = SecurityUtils.isComponentVisible(component.getClass());
        } else if (component instanceof BookmarkablePageLink<?>) {
            BookmarkablePageLink<?> link = (BookmarkablePageLink<?>) component;
            ret = SecurityUtils.isComponentVisible(link.getPageClass());
        } else {
            ret = true;
        }
        return ret;
    }

    private boolean isComponentAllowed(String aPath, Properties aProps) {
        String line = aProps.getProperty(aPath);
        StringTokenizer st = new StringTokenizer(line, "; , \t");
        while(st.hasMoreTokens()) {
            if(SecurityUtils.isUserInRole(st.nextToken())) {
                return true;
            }
        }
        return false ;
    }

    private boolean isInSecurityPath(String aPath, Properties aProps) {
        return aProps.containsKey(aPath);
    }

    private Properties loadSecurityProperties() {
        Properties prop = new Properties();
        String file = DEV_FILE_PATH;
        boolean devMode = new File(file).exists();
        InputStream in = null;
		try {
			if (devMode) {
				in = new FileInputStream(file);
			} else {
				if (cachedProperties != null) {
					return cachedProperties;
				}
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				if (cl == null) {
					cl = getClass().getClassLoader();
				}
				in = cl.getResourceAsStream(PROD_FILE_PATH);
			}
		    prop.load(in);
		    if (!devMode) {
				cachedProperties = prop;
			}
			return prop;
		} catch (IOException e) {
		    throw new IllegalStateException("Error reading from file " +file+": "+e.getMessage());
		} finally {
		    try {
		        if (in != null) {
					in.close();
				}
		    } catch (IOException e) {
		        throw new IllegalStateException("Error closing file " +file+": "+e.getMessage(), e);
		    }
		}
    }
}
